// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.


`define SEC_GLOBAL_MAX_ADDR  7 // define how many DW registers are used
//Define Address for each regiter
`define SEC_GLB_FPGA_VERSION_ADDR       16'h00
`define SEC_GLB_REV_CTRL_ADDR           16'h04
`define SEC_GLB_BUILD_TIME_ADDR         16'h08
`define SEC_GLB_BUILD_CATEGORY_ADDR     16'h0C
`define SEC_GLB_DEVICE_LOCATION_ADDR    16'h10
`define SEC_GLB_SCRATCH_ADDR            16'h14
`define SEC_GLB_HP_SLOT_LED_ADDR        16'h18
`define SEC_GLB_POSTCODE_VALUE          16'h1C

//Define Default Value
`define SEC_GLB_MAJOR_RELEASE_NUM_DEF  16'h00
`define SEC_GLB_MINOR_RELEASE_NUM_DEF  16'h17

`define SEC_GLB_GIT_HASH_DEF           32'h1

`define SEC_GLB_BUILD_YEAR_DEF         04'h1
`define SEC_GLB_BUILD_MONTH_DEF        04'h6
`define SEC_GLB_BUILD_DAY_DEF          08'h2
`define SEC_GLB_BUILD_HOUR_DEF         08'h3
`define SEC_GLB_BUILD_MINUTE_DEF       08'h4

`define SEC_GLB_BUILD_CATEGORY_DEF     01'b0  //Clean Build
`define SEC_GLB_DEVICE_LOCTAION_DEF    08'h11 //debug CPLD


module secondary_global_csr 
(
    input clk,
    input reset,

    //avmm interface
    input      [31:0] avmm_address,
    input             avmm_write,
    input      [31:0] avmm_writedata,          
    input             avmm_read,     
    output reg [31:0] avmm_readdata,      
    output reg        avmm_readdatavalid, 
    output            avmm_waitrequest,           
    input      [ 3:0] avmm_byteenable,
	 
    //error report
    output            invalid_access,
    //Hot-plug LED signal
    inout      [ 3:0 ] ihp_slot_led,
    input      [ 7:0 ] bios_postcode 
);

wire [15:0] addr_local; //Only 16 bits out of 32 bits avmm_address supported
reg  [31:0] scm_global_reg [`SEC_GLOBAL_MAX_ADDR-1:0]; //local register
reg  [31:0] illegal_write;

reg         invalid_read;
reg         invalid_write;

assign avmm_waitrequest = 1'b0; //Fix wait request to 1'b0 as no wait needed

assign addr_local = avmm_address[15:0];

assign invalid_access   =  invalid_write || invalid_read;

//invalid_read, using combinational logic to report error
always @ ( * ) begin
    if ( reset ) begin
        invalid_read       = 1'b0;
    end else begin
        if ( avmm_read && !( |avmm_address[31:16]) && (&avmm_byteenable)) begin
            case (addr_local)
                 `SEC_GLB_FPGA_VERSION_ADDR    : begin 
					     invalid_read           =   1'b0;
                 end
                 `SEC_GLB_REV_CTRL_ADDR        : begin
					     invalid_read           =   1'b0;
                 end
                 `SEC_GLB_BUILD_TIME_ADDR      : begin
                    invalid_read           =   1'b0;
                 end						  
                 `SEC_GLB_BUILD_CATEGORY_ADDR  : begin
					     invalid_read           =   1'b0;
                 end
                 `SEC_GLB_DEVICE_LOCATION_ADDR : begin
					     invalid_read           =   1'b0;
                 end
                 `SEC_GLB_SCRATCH_ADDR         : begin
                    invalid_read           =   1'b0;
                 end  
                 `SEC_GLB_HP_SLOT_LED_ADDR     : begin
                    invalid_read           =   1'b0;
                 end  
                 `SEC_GLB_POSTCODE_VALUE    : begin
                    invalid_read           =   1'b0;
                 end  
                 default                       : begin
					     invalid_read           =   1'b1;
                 end
            endcase
        end
		  else begin
		     invalid_read                    =   1'b0;
        end
    end
end

//read registers
always @ ( posedge clk ) begin
    if ( reset ) begin
        avmm_readdata <= 32'h0;
    end else begin
        if ( avmm_read && !( |avmm_address[31:16]) && (&avmm_byteenable)) begin
            case (addr_local)
                 `SEC_GLB_FPGA_VERSION_ADDR    : avmm_readdata <= {8'b0, `SEC_GLB_MAJOR_RELEASE_NUM_DEF, 8'b0, `SEC_GLB_MINOR_RELEASE_NUM_DEF};
                 `SEC_GLB_REV_CTRL_ADDR        : avmm_readdata <=  `SEC_GLB_GIT_HASH_DEF;
                 `SEC_GLB_BUILD_TIME_ADDR      : avmm_readdata <= {`SEC_GLB_BUILD_YEAR_DEF,
                                                                   `SEC_GLB_BUILD_MONTH_DEF,
                                                                   `SEC_GLB_BUILD_DAY_DEF,
                                                                   `SEC_GLB_BUILD_HOUR_DEF,
                                                                   `SEC_GLB_BUILD_MINUTE_DEF };
                 `SEC_GLB_BUILD_CATEGORY_ADDR  : avmm_readdata <= {31'h0, `SEC_GLB_BUILD_CATEGORY_DEF};
                 `SEC_GLB_DEVICE_LOCATION_ADDR : avmm_readdata <= {30'h0, `SEC_GLB_DEVICE_LOCTAION_DEF};
                 `SEC_GLB_SCRATCH_ADDR         : avmm_readdata <= scm_global_reg[`SEC_GLB_SCRATCH_ADDR / 4];   
                 `SEC_GLB_HP_SLOT_LED_ADDR     : avmm_readdata <= {28'h0, ihp_slot_led};
                 `SEC_GLB_POSTCODE_VALUE       : avmm_readdata <= {24'h0, bios_postcode};
                 default                       : avmm_readdata <= 32'hFFFF_FFFF; //reture bad addr
            endcase
        end
    end
end

always @ ( posedge clk ) begin
    if ( reset ) begin
        avmm_readdatavalid <= 1'b0;
    end else begin
        if ( avmm_read && (&avmm_byteenable) && (!invalid_read)) begin
            avmm_readdatavalid <= 1'b1; //readvalid asserts one clock cycle after read assetted.
        end else begin
            avmm_readdatavalid <= 1'b0;
        end
    end
end

//invalid_write, using combinational logic to report error
always @ ( * ) begin
    if ( reset ) begin
		  invalid_write                 = 1'b0;
    end else begin
        if ( avmm_write && !( |avmm_address[31:16]) && (&avmm_byteenable)) begin
            case (addr_local)
                `SEC_GLB_SCRATCH_ADDR             : begin
		              invalid_write                                        =   1'b0;
                 end
                default                           : begin
		             invalid_write                                         =   1'b1;
                end
            endcase
        end
	     else begin
	        invalid_write              =   1'b0;
        end
    end
end

//write registers
always @ ( posedge clk ) begin
    if ( reset ) begin
        scm_global_reg[`SEC_GLB_SCRATCH_ADDR/4] <= 32'h0;
    end else begin
        if ( avmm_write && !( |avmm_address[31:16]) && (&avmm_byteenable)) begin
            case (addr_local)
                `SEC_GLB_SCRATCH_ADDR    : scm_global_reg[`SEC_GLB_SCRATCH_ADDR/4] <= avmm_writedata;
                default                  : illegal_write                           <= avmm_writedata; //reture bad addr
            endcase
        end
    end
end

endmodule    